# -*- coding: utf8 -*-

from django.db import models
from django.contrib.auth.models import User


####################
# Helper functions #
####################

def teacher_from_user(user):
    try:
        return user.get_profile().is_teacher()
    except:
        return False
User.teacher = teacher_from_user

def teacher_from_id(id):
    try:
        user = User.objects.get(id=id)
        return teacher_from_user(user)
    except:
        return False

def student_from_user(user, specialization=None):
    try:
        return user.get_profile().is_student(specialization)
    except:
        return False
User.student = student_from_user

def student_from_id(id):
    try:
        user = User.objects.get(id=id)
        return student_from_user(user)
    except:
        return False

def dean_from_user(user):
    try:
        return user.get_profile().is_dean()
    except:
        return False
User.dean = dean_from_user

def dean_from_id(id):
    try:
        user = User.objects.get(id=id)
        return dean_from_user(user)
    except:
        return False

def add_profile(user):
    profile = UserProfile()
    user.userprofile_set.add(profile)
    user.save()


##########
# Models #
##########

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)

    def is_student(self, specialization=None):
        if specialization:
            return self.student_set.filter(specialization=specialization)
        else:
            return self.student_set.all()

    def is_teacher(self):
        try:
            teacher = self.teacher
            if isinstance(teacher, Teacher):
                return teacher
            else:
                return False
        except:
            return False

    def is_dean(self):
        try:
            dean = self.dean
            if isinstance(dean, Dean):
                return dean
            else:
                return False
        except:
            return False

    def user_type_name(self):
        if self.is_teacher():
            return 'Opiekun praktyk'
        elif self.is_dean():
            return 'Dziekanat'
        elif self.is_student():
            return 'Student'
        else:
            return ''

    def get_specializations(self):
        if self.is_student():
            return [i.specialization for i in self.is_student()]
        elif self.is_teacher():
            return [i for i in self.is_teacher().specialization_set.all()]
        else:
            return [i for i in self.is_dean().faculty.specialization_set.all()]

    def __unicode__(self):
        return self.user.first_name + ' ' + self.user.last_name


class Faculty(models.Model):
    full_name = models.CharField(max_length=80)
    short_name = models.CharField(max_length=5)

    def __unicode__(self):
        return self.short_name


class Teacher(models.Model):
    degree = models.CharField(max_length=25)
    phone = models.CharField(max_length=30)
    address = models.CharField(max_length=100)
    profile = models.OneToOneField(UserProfile)
    faculty = models.ForeignKey(Faculty)

    def user(self):
        return self.profile.user

    def __unicode__(self):
        return unicode(self.profile)

    def get_address(self):
        return address

    def governs_specialization(self, specialization):
        if type(specialization) == str or type(specialization) == unicode:
            specialization = int(specialization)
        if type(specialization) == int:
            specialization = Specialization.objects.get(id=specialization)
        return self.id == specialization.teacher.id

    def can_edit_student(self, student):
        try:
            self.specialization_set.get(id=student.specialization.id)
            return True
        except:
            return False


class Specialization(models.Model):
    full_name = models.CharField(max_length=100)
    faculty = models.ForeignKey(Faculty)
    teacher = models.ForeignKey(Teacher)

    def active_students(self):
        students = self.student_set.all()
        return filter(lambda x: x.is_registered(), students)

    def unregistered_students(self):
        students = self.student_set.all()
        return filter(lambda x: not x.is_registered(), students)

    def __unicode__(self):
        return self.full_name


class Dean(models.Model):
    profile = models.OneToOneField(UserProfile)
    faculty = models.ForeignKey(Faculty)

    def user(self):
        return self.profile.user

    def __unicode__(self):
        return unicode(self.profile)


class Student(models.Model):
    book_no = models.CharField(max_length=20)
    specialization = models.ForeignKey(Specialization)
    year_of_study = models.PositiveIntegerField()
    profile = models.ForeignKey(UserProfile)

    def user(self):
        return self.profile.user

    def is_registered(self):
        user = self.user()
        return user.username != self.book_no

    def __unicode__(self):
        return unicode(self.profile)

    def latest_training(self):
        trainings = self.training_set.latest()

    def get_address(self):
        return '%s %s %s' % (self.street,
                             self.postal_code,
                             self.city)

    def add_training(self):
        training = Training.objects.create(student=self)
        training.save()

    def recent_training(self):
        return self.training_set.order_by('-training_date')[0]

    @classmethod
    def new(cls, first_name, last_name,
            book_no, specialization,
            year_of_study=3, add_training=True):

        profiles = Student.objects.filter(book_no=book_no)
        if profiles:
            profile = profiles[0].profile
            same_spec = profiles.filter(specialization=specialization)
            if same_spec:
                student = same_spec[0]
            else:
                student = Student.objects.create(book_no=book_no,
                                                 specialization=specialization,
                                                 year_of_study=year_of_study,
                                                 profile=profile)
                student.save()
        else:
            user = User.objects.create_user(book_no, '', book_no)
            user.is_active = False
            user.first_name = first_name
            user.last_name = last_name
            add_profile(user)
            user.save()
            student = Student.objects.create(book_no=book_no,
                                             specialization=specialization,
                                             year_of_study=year_of_study,
                                             profile=user.get_profile())
            student.save()
        if add_training:
            student.add_training()
        return student


class Branch(models.Model):
    main_branch = models.ForeignKey('self', verbose_name='Siedziba główna', null=True, blank=True)
    name = models.CharField('Nazwa firmy', max_length=100)
    street = models.CharField('Ulica', max_length=100)
    postal_code = models.CharField('Kod pocztowy', max_length=100)
    city = models.CharField('Miasto', max_length=100)
    country = models.CharField(u'Państwo', max_length=100, default='Polska')
    created_by = models.ForeignKey(User)

    def __unicode__(self):
        return u' '.join((self.name, self.street, self.postal_code,
                          self.city, self.country))

    def is_main_branch(self):
        return self.main_branch == None

    def get_address(self):
        return '%s %s %s' % (self.street,
                             self.postal_code,
                             self.city)

    @classmethod
    def main_branches(cls):
        return cls.objects.filter(main_branch__isnull=True)

    class Meta:
        ordering = ['name', 'country', 'city', 'street']


class Training_Insurance(models.Model):
    name = models.CharField(max_length=100)

    def __unicode__(self):
        return self.name


class Training_Date(models.Model):
    specialization = models.ForeignKey(Specialization)
    start_date = models.DateField(verbose_name=u'Data rozpoczęcia')
    end_date = models.DateField(verbose_name=u'Data zakończenia')

    def __unicode__(self):
        return '%s - %s' % (self.start_date, self.end_date)

    class Meta:
        ordering = ['start_date', 'end_date']


class Training(models.Model):
    MARKS = ['ndst', 'dst', 'dst+', 'db', 'db+', 'bdb', 'cel']

    student = models.ForeignKey(Student)
    branch = models.ForeignKey(Branch, verbose_name='Firma', null=True)
    training_date = models.ForeignKey(Training_Date,
                                      verbose_name='Termin praktyki',
                                      null=True)
    street = models.CharField(max_length=100,
                              verbose_name='Ulica',
                              null=True)
    postal_code = models.CharField(max_length=100,
                                   verbose_name='Kod pocztowy',
                                   null=True)
    city = models.CharField(max_length=100,
                            verbose_name='Miasto',
                            null=True)
    is_foreigner = models.BooleanField(verbose_name='Student zagraniczny')

    hostel = models.BooleanField('Potrzebny akademik')
    payable = models.BooleanField('Praktyka płatna')
    contract_date = models.DateField('Data zawarcia umowy',
                                     null=True, blank=True)
    pass_date = models.DateField('Data zaliczenia', null=True, blank=True)
    remarks = models.CharField('Uwagi', max_length=100, null=True)
    locked = models.BooleanField('Zablokowane', default=False)

    insurance_company = models.ForeignKey(Training_Insurance,
                                          verbose_name='Ubezpieczyciel',
                                          null=True,
                                          blank=True)
    insurance_number = models.CharField('Numer ubezpieczenia',
                                        max_length=100,
                                        null=True,
                                        blank=True)

    dont_print_contract = models.BooleanField('Nie drukuj umowy')
    mark = models.CharField('Ocena', max_length=5, null=True, blank=True)
    is_working = models.BooleanField('Student pracuje')
    socrates = models.BooleanField('Program Socrates', default=False)
    is_archival = models.BooleanField('Archiwalna', default=False)

    def __unicode__(self):
        return unicode(self.student) + ' (' + unicode(self.branch) + ')'

    def abroad(self):
        return self.branch.country != 'Polska'


class Message(models.Model):
    sender = models.ForeignKey(User, related_name='sent')
    deleted_by_sender = models.BooleanField(default=False)
    recipient = models.ForeignKey(User, related_name='inbox')
    deleted_by_recipient = models.BooleanField(default=False)
    topic = models.CharField(max_length=100)
    body = models.TextField()
    is_read = models.BooleanField()
    send_date = models.DateTimeField()

    def __unicode__(self):
        return self.topic


class Setting(models.Model):
    key = models.CharField(max_length=50)
    value = models.CharField(max_length=300)

    def __unicode__(self):
        return self.key + ':' + self.value

    @staticmethod
    def default_insurance_company(change=None):
        if change:
            try:
                setting = Setting.objects.get(key='default_insurance_company')
                setting.value = str(change.id)
            except Setting.DoesNotExist:
                setting = Setting(key='default_insurance_company',
                                  value=str(change.id))
            setting.save()
            return change
        else:
            setting = Setting.objects.get(key='default_insurance_company')
            company = Training_Insurance.objects.get(id=setting.value)
            return company

    @staticmethod
    def default_insurance(change=None):
        if change:
            try:
                setting = Setting.objects.get(key='default_insurance')
                setting.value = change
            except Setting.DoesNotExist:
                setting = Setting(key='default_insurance',
                                  value=change)
            setting.save()
            return change
        else:
            setting = Setting.objects.get(key='default_insurance')
            return setting.value

    @staticmethod
    def get_or_none(key):
        try:
            setting = Setting.objects.get(key=key)
            return setting.value
        except Setting.DoesNotExist:
            return None

    @staticmethod
    def email_address():
        setting = Setting.objects.get(key='email_address')
        return setting.value

    @staticmethod
    def email_user():
        return Setting.get_or_none('email_user')

    @staticmethod
    def email_password():
        return Setting.get_or_none('email_password')

